use crate::fs;
use io::{Read, Write};
use std::fs::{remove_file, File};
use std::io;
use std::path;

pub struct Config {
    pub path: String,
}

pub struct Client {
    cfg: Config,
}

impl Client {
    pub fn new(cfg: Config) -> Client {
        Client { cfg: cfg }
    }
}

impl fs::FS for Client {
    fn read(&self, name: &str) -> Result<String, io::Error> {
        let path = path::Path::new(self.cfg.path.as_str()).join(name);
        println!("read, name:{}, path:{:?}", name, path);

        let mut buf = String::new();
        File::open(path)?.read_to_string(&mut buf)?;
        Ok(buf)
    }

    fn read_to_writer(&self, name: &str, w: &mut dyn io::Write) -> io::Result<()> {
        let path = path::Path::new(self.cfg.path.as_str()).join(name);
        println!("read_to_writer, name:{}, path:{:?}", name, path);

        let mut file = File::open(path)?;
        io::copy(&mut file, w)?;

        Ok(())
    }

    fn write(&self, name: &str, content: &str) -> io::Result<()> {
        let path = path::Path::new(self.cfg.path.as_str()).join(name);
        println!("write, name:{}, path:{:?}", name, path);

        File::create(path)?.write_all(content.as_bytes())
    }

    fn write_from_reader(&self, name: &str, r: &mut dyn io::Read) -> io::Result<()> {
        let path = path::Path::new(self.cfg.path.as_str()).join(name);
        println!("write_from_reader, name:{}, path:{:?}", name, path);

        let mut file = File::create(path)?;
        io::copy(r, &mut file)?;

        Ok(())
    }

    fn delete(&self, name: &str) -> io::Result<()> {
        let path = path::Path::new(self.cfg.path.as_str()).join(name);
        println!("delete, name:{}, path:{:?}", name, path);
        remove_file(path)
    }
}

impl From<fs::Type> for Client {
    fn from(cfg: fs::Type) -> Self {
        let cfg = match cfg {
            fs::Type::Local(cfg) => cfg,
            fs::Type::Ufile(_) => {
                panic!("config invalid");
            }
        };
        Client { cfg: cfg }
    }
}
